package com.boarsoft.sofa;

import static com.boarsoft.common.util.JsonMapping.mapping;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import javax.annotation.PostConstruct;

import org.apache.commons.lang.NotImplementedException;
import org.jboss.logging.MDC;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.core.env.Environment;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alipay.hessian.generic.model.GenericArray;
import com.alipay.hessian.generic.model.GenericCollection;
import com.alipay.hessian.generic.model.GenericMap;
import com.alipay.hessian.generic.model.GenericObject;
import com.alipay.sofa.rpc.api.AlipayGenericContext;
import com.alipay.sofa.rpc.api.GenericService;
//import com.alipay.sofa.rpc.boot.container.ProviderConfigContainer;
import com.alipay.sofa.rpc.common.MockMode;
import com.alipay.sofa.rpc.common.RpcConstants;
import com.alipay.sofa.rpc.config.ApplicationConfig;
import com.alipay.sofa.rpc.config.ConsumerConfig;
import com.alipay.sofa.rpc.config.MethodConfig;
import com.alipay.sofa.rpc.config.ProviderConfig;
import com.alipay.sofa.rpc.config.RegistryConfig;
import com.alipay.sofa.rpc.config.ServerConfig;
import com.alipay.sofa.rpc.context.RpcInvokeContext;
import com.alipay.sofa.rpc.core.exception.RpcErrorType;
import com.alipay.sofa.rpc.core.exception.SofaRpcException;
import com.alipay.sofa.rpc.core.invoke.SofaResponseCallback;
import com.alipay.sofa.rpc.core.request.RequestBase;
import com.alipay.sofa.rpc.core.request.SofaRequest;
import com.alipay.sofa.rpc.core.response.SofaResponse;
import com.alipay.sofa.rpc.registry.Registry;
import com.alipay.sofa.rpc.registry.RegistryFactory;
import com.boarsoft.common.Util;
import com.boarsoft.common.util.HttpClientUtil;
import com.boarsoft.rpc.RpcCallback;
import com.boarsoft.rpc.RpcConfig;
import com.boarsoft.rpc.adapter.RpcProtocolAdapter;
import com.boarsoft.rpc.adapter.RpcProtocolExtension;
import com.boarsoft.rpc.bean.RpcFaceConfig;
import com.boarsoft.rpc.bean.RpcMethodConfig;
import com.boarsoft.rpc.bean.RpcReferenceConfig;
import com.boarsoft.rpc.bean.RpcServiceConfig;
import com.boarsoft.rpc.core.RpcContext;
import com.boarsoft.rpc.core.RpcCore;
import com.boarsoft.rpc.generalize.RpcGenArray;
import com.boarsoft.rpc.generalize.RpcGenCollection;
import com.boarsoft.rpc.generalize.RpcGenList;
import com.boarsoft.rpc.generalize.RpcGenMap;
import com.boarsoft.rpc.generalize.RpcGenMocker;
import com.boarsoft.rpc.generalize.RpcGenObj;
import com.boarsoft.rpc.generalize.RpcGenSet;
import com.boarsoft.soagov.config.SvcConfig;
import com.boarsoft.soagov.spy.SpyData;
import com.boarsoft.soagov.spy.SvcSpy;
import com.boarsoft.sofa.config.MyConsumerConfig;
import com.boarsoft.sofa.config.ProviderInfoListenerFactory;
import com.boarsoft.sofa.converter.GenObjConverter;

public class SofaAdapter implements RpcProtocolAdapter {
	private static final Logger log = LoggerFactory.getLogger(SofaAdapter.class);
	/** */
	@Autowired
	protected DefaultListableBeanFactory proxyFactory;
	@Autowired
	protected ApplicationContext applicationContext;
	@Autowired
	private Environment env;

	@Autowired(required = false)
	protected SvcSpy svcSpy;
	@Autowired
	protected RpcContext rpcContext;

	@Autowired(required = false)
	protected RpcProtocolExtension protocolEx;

	protected ApplicationConfig application;
	protected ServerConfig serverConfig;
	protected RegistryConfig registryConfig;

	/** SOFA Service Mesh 开关 */
	protected final String MESH_MOSN_ENABLE = "MOSN_ENABLE";
	protected final String MESH_REG_ADDRESS = "http://127.0.0.1:13330";
	protected final String MESH_REG_PROTOCOL = "mesh";

	protected String appName;
	protected String regAddress;
	protected int localPort = 12200;
	protected String rpcProtocol = "bolt";
	protected String regProtocol = "sofa";
	protected int registTimeout = 3000;
	protected int addressWait;
	protected boolean subscribe = true;
	protected final String DEFAULT_PROTOCOL = "sofa";
	protected ServerConfig myServerConfig = new ServerConfig()//
			.setPort(RpcConfig.getPort()).setDaemon(false)//
			.setProtocol(RpcFaceConfig.PROTOCOL_DEFAULT);
	// 是否集成 sofa boot
	protected boolean sofaBoot = false;

	protected Map<String, Future<Object>> referMap = new ConcurrentHashMap<>();
	protected Map<String, CountDownLatch> locksMap = new ConcurrentHashMap<>();

	protected List<ProviderInfoListenerFactory> listenerFactories = new ArrayList<>();

	@PostConstruct
	public void init() {
		// 进行一些与平台有关的初始化动作
		if (protocolEx != null) {
			protocolEx.beforeInit(this);
		}
// 已挪到 protocolEx.beforeInit 中
//		// 默认添加RpcProviderInfoListener的工厂类
//		listenerFactories.add(new ProviderInfoListenerFactory() {
//			@Override
//			public ProviderInfoListener getObject() {
//				return new RpcProviderInfoListener(rpcContext);
//			}
//		});
		// service mesh 开关
		String mesh = System.getenv(MESH_MOSN_ENABLE);
		if ("true".equals(mesh)) {
			regAddress = MESH_REG_ADDRESS;
			regProtocol = MESH_REG_PROTOCOL;
		}
		log.info("Registry protocol = {}, address = {}", regProtocol, regAddress);
		application = new ApplicationConfig().setAppName(appName);
		serverConfig = new ServerConfig().setPort(localPort)//
				.setProtocol(rpcProtocol).setDaemon(false);
		registryConfig = new RegistryConfig().setAddress(regAddress)//
				.setProtocol(regProtocol);
		Registry registry = RegistryFactory.getRegistry(registryConfig);
		registry.init();
		registry.start();
	}

	@SuppressWarnings("unchecked")
	@Override
	public boolean registService(RpcServiceConfig sc, boolean export) throws ClassNotFoundException {
		if ("mac-rpc".equals(sc.getGroup())) {
			return true;
		}
		// 构建 ProviderConfig
		Object ref = applicationContext.getBean(sc.getRef());
		ProviderConfig<Object> pc = (ProviderConfig<Object>) new ProviderConfig<>()//
				.setRegistry(registryConfig)//
				.setInterfaceId(sc.getInterfaceClazz().getName())//
				.setApplication(application)//
				.setRef(ref)//
				// .setGroup(sc.getGroup())
				// .setVersion(sc.getVersion());
				.setTimeout(sc.getTimeout())//
				.setMethods(new HashMap<String, MethodConfig>())//
//				.setParameter("sign", sc.getSign())// 传递serviceKey  发布接口时不绑定sign,降低rpc传输量
				.setParameter("tag", System.getProperty("rpc.tag", "Z"))//
				.setParameter("zone", System.getProperty("com.alipay.ldc.zone", System.getProperty("my.zone")))
				.setParameter("readOnly", env.getProperty("rpc.readOnly", String.valueOf(false)))//
				.setRegister(!this.sofaBoot); // 集成SofaBoot时统一由SofaBootRpcStartListener负责注册
		// 如果有配置mocker
		String mocker = sc.getMocker();
		if (Util.strIsNotEmpty(mocker)) {
			if (applicationContext.containsBean(mocker)) {
				pc.setMockRef(applicationContext.getBean(mocker));
				pc.setMockMode(MockMode.LOCAL);
				// cc.setMock(rc.isAutoMock());
			} else {
				log.warn("Can not find mocker bean {}", mocker);
			}
		}
		// 登记方法配置
//		Map<String, RpcMethodConfig> mmcMap = sc.getMethodConfigMap();
//		this.registMethods(mmcMap, pc.getMethods());
		Registry reg = RegistryFactory.getRegistry(registryConfig);
//		// 通过自定义参数传递方法relativeId
//		for (RpcMethodConfig mm : mmcMap.values()) {
//			pc.setParameter(mm.getKey(), new StringBuilder("relativeId:")//
//					.append(mm.getRelativeId()).toString());
//		}
		// export
		if (export) {
			log.info("Export service {}", sc.getSign());
			pc.setServer(serverConfig).export();
		} else {
			// 只注册，不Export
			pc.setServer(myServerConfig);
			log.info("Regist service {}", sc.getSign());
			reg.register(pc);
		}
		// 已挪到 protocolEx.afterRegistService
		// providerConfigContainer.addProviderConfig(buildProviderConfigKey(pc,sc,":"),pc);
		if (protocolEx != null) {
			Map<String, Object> pm = new HashMap<>();
			pm.put("ProviderConfig", pc);
			protocolEx.afterRegistService(this, sc, pm);
		}
		return true;
	}

//	private String buildProviderConfigKey(ProviderConfig<Object> pc, RpcServiceConfig sc, String split){
//		return pc.getInterfaceId().concat(split).concat(sc.getVersion()).concat(split).concat(sc.getProtocol());
//	}

	protected ConsumerConfig<?> buildConsumerConfig(RpcReferenceConfig rc) {
		// 构建 ConsumerConfig
		ConsumerConfig<Object> cc = new MyConsumerConfig<>()//
				.addListeners(listenerFactories)
				.setApplication(application)//
				.setRegistry(registryConfig)//
				.setInterfaceId(rc.getInterfaceName())//
				.setGeneric(rc.isGeneralized())//
				.setId(rc.getId())
				// .setGroup(rc.getGroup())
				// .setVersion(rc.getVersion())
				.setProtocol(rc.getProtocol())//
				.setTimeout(rc.getTimeout())//
				.setDirectUrl(rc.getDirect())//
				.setMethods(new HashMap<String, MethodConfig>())//
				.setAddressWait(addressWait)//
				.setParameter("tag", System.getProperty("rpc.tag", "Z"))//
				.setRegister(true)//
				.setSubscribe(subscribe);
		//
		if (Util.strIsEmpty(rc.getProtocol())) {
			cc.setProtocol(RpcFaceConfig.PROTOCOL_DEFAULT);
		}
		// 如果有配置mocker
		String mocker = rc.getMocker();
		if (Util.strIsNotEmpty(mocker)) {
			if (applicationContext.containsBean(mocker)) {
				cc.setMockRef(applicationContext.getBean(mocker));
				cc.setMockMode(MockMode.LOCAL);
				// cc.setMock(rc.isAutoMock());
			} else {
				log.warn("Can not find mocker bean {}", mocker);
			}
		}
		return cc;
	}

	@Override
	public Object referReference(RpcReferenceConfig rc)
			throws ClassNotFoundException, InterruptedException, ExecutionException, TimeoutException {
		Future<Object> ft = this.registReference(rc);
		return ft.get(registTimeout, TimeUnit.MILLISECONDS);
	}

	@Override
	@SuppressWarnings("unchecked")
	public <T> T referReference(RpcReferenceConfig rc, Class<T> clazz)
			throws ClassNotFoundException, InterruptedException, ExecutionException, TimeoutException {
		Future<Object> ft = this.registReference(rc);
		return (T) ft.get(registTimeout, TimeUnit.MILLISECONDS);
	}

	@Override
	public Future<Object> registReference(RpcReferenceConfig rc) throws ClassNotFoundException, InterruptedException {
		// 进行一些与平台有关的初始化动作
		if (protocolEx != null) {
			protocolEx.beforeRegistReference(this, rc);
		}
		ExecutorService es = RpcCore.getCurrentInstance().getThreadPool();
		if ("mac-rpc".equals(rc.getGroup())) {
			return es.submit(new Callable<Object>() {
				@Override
				public Object call() throws Exception {
					return applicationContext.getBean(rc.getId(), rc.getInterfaceClazz());
				}
			});
		}
		// 为了避免交易中心调用不同包名相同类名的api，交易中心没有consume.xml的情况下，使用beanID拿不到正确服务，用sign作为key去保存服务引用
		String key = rc.getSign();
		Future<Object> ro = referMap.get(key);
		if (ro != null) {
			return ro;
		}
		synchronized (referMap) {
			ro = referMap.get(key);
			if (ro != null) {
				return ro;
			}
			ConsumerConfig<?> cc = this.buildConsumerConfig(rc);
			cc.setProtocol(rpcProtocol);
			if (rc.isGeneralized()) {
				log.info("Create generic refer of {}", rc);
				ro = es.submit(new Callable<Object>() {
					@Override
					public Object call() throws Exception {
						return cc.refer();
					}
				});
			} else {
				log.info("Create reference factory for {}", rc);
				// 设置通信协议
				BeanDefinitionBuilder bdb = BeanDefinitionBuilder//
						.genericBeanDefinition(SofaReferenceFactory.class);
				// bdb.addPropertyValue("refObject", ref);
				bdb.addPropertyValue("consumerConfig", cc);
				bdb.addPropertyValue("refClazz", rc.getInterfaceClazz());
				AbstractBeanDefinition abd = bdb.getRawBeanDefinition();
				proxyFactory.registerBeanDefinition(rc.getId(), abd);
				// 异步获取此bean，触发refer动作，避免首次调用高耗时
				ro = es.submit(new Callable<Object>() {
					@Override
					public Object call() throws Exception {
						return applicationContext.getBean(rc.getId(), rc.getInterfaceClazz());
					}
				});
			}
			referMap.put(key, ro);
			rpcContext.getMyRegistry().getReferenceMap().put(key, rc);
			return ro;
		}
	}

	@Override
	public boolean subscribe(RpcReferenceConfig rc, boolean await) throws ClassNotFoundException, InterruptedException {
		String key = rc.getSign();
		if (locksMap.containsKey(key)) {
			return true;
		}
		synchronized (locksMap) {
			if (locksMap.containsKey(key)) {
				return true;
			}
			locksMap.put(key, new CountDownLatch(1));
			ConsumerConfig<?> cc = this.buildConsumerConfig(rc);
			cc.setProtocol(RpcFaceConfig.PROTOCOL_DEFAULT)// 设置通信协议
					.setSubscribe(true); // 订阅服务
		}
		if (await) {
			locksMap.get(key).await(registTimeout, TimeUnit.MILLISECONDS);
		}
		return true;
	}

	/**
	 * 集中处理服务暴露和引用的方法配置
	 *
	 * @param mmMap
	 *            mac-rpc 方法配置
	 * @param smMap
	 *            sofa-rpc 方法配置
	 */
	protected void registMethods(Map<String, RpcMethodConfig> mmMap, Map<String, MethodConfig> smMap) {
		for (RpcMethodConfig mmc : mmMap.values()) {
			// 获取并设置方法名
			MethodConfig smc = new MethodConfig();
			String ms = mmc.getSign();
			String mn = ms.substring(0, ms.indexOf("(") - 1);
			smc.setName(mn);
			// 填充参数表
			Map<String, String> pm = new HashMap<>();
			for (Parameter p : mmc.getParameters()) {
				pm.put(p.getName(), p.getType().getName());
			}
			smc.setParameters(pm);
			// 设置已兼容的属性
			smc.setTimeout(mmc.getTimeout());
			// 设置调用类型
			switch (mmc.getType()) {
				case RpcMethodConfig.TYPE_SYNC_CALL:
					smc.setInvokeType(RpcConstants.INVOKER_TYPE_SYNC);
					break;
				case RpcMethodConfig.TYPE_ASYNC_CALL:
					// 默认是future类型，配了callback才是callback类型
					smc.setInvokeType(RpcConstants.INVOKER_TYPE_FUTURE);
					break;
				case RpcMethodConfig.TYPE_SYNC_NOTICE:
				case RpcMethodConfig.TYPE_ASYNC_NOTICE:
					smc.setInvokeType(RpcConstants.INVOKER_TYPE_ONEWAY);
					break;
				default:
					throw new NotImplementedException("SOFA不支持此方法的调用类型：".concat(mmc.getKey()));
			}
			// 配置回调方法
			if (Util.strIsNotEmpty(mmc.getCallback())) {
				// 如果配置的callback，修改调用类型，并构建回调方法
				smc.setInvokeType(RpcConstants.INVOKER_TYPE_CALLBACK);
				//
				RpcCallback mc = applicationContext.getBean(mmc.getCallback(), RpcCallback.class);
				smc.setOnReturn(new SofaResponseCallback<Object>() {

					@Override
					public void onAppResponse(Object appResponse, String methodName, RequestBase request) {
						mc.callback(appResponse, null, request.getMethodArgs());
					}

					@Override
					public void onAppException(Throwable throwable, String methodName, RequestBase request) {
						mc.callback(null, throwable, request.getMethodArgs());
					}

					@Override
					public void onSofaException(SofaRpcException sofaException, String methodName, RequestBase request) {
						mc.callback(null, sofaException, request.getMethodArgs());
					}
				});
			}
			smMap.put(mn, smc);
		}
	}

	@Override
	public Object invoke(RpcReferenceConfig rc, RpcMethodConfig rmc, Object[] args) throws Exception {
		Future<Object> ft = null;
		if (rc.isGeneralized()) {
			ft = this.registReference(rc);
		}
		Object[] ta = new Object[args.length];
		for (int i = 0; i < args.length; i++) {
			ta[i] = this.checkIn(args[i]);
		}
		String sign = rmc.getSign();
		int i = sign.indexOf("(");
		String mn = sign.substring(0, i);
		String pm = sign.substring(i + 1, sign.length() - 1);
		Object ro = this.invoke(ft, rc, rmc, mn, pm, ta);
		return this.checkOut(ro);
	}

	@SuppressWarnings("deprecation")
	private Object invoke(Future<Object> ft, RpcReferenceConfig rc, RpcMethodConfig rmc, String mn, String pm, Object[] args)
			throws Exception {
		// 服务治理埋点，如果svcSpy不为空，且服务状态为关闭，则尝试使用mocker
		if (svcSpy != null) {
			String key = rmc.getKey();
			SpyData sd = svcSpy.getSpyData(key);
			int status = svcSpy.checkStatus(sd);
			// 检查服务的开关状态，与是否开启了结果模拟
			if (status == SvcConfig.STATUS_DISABLE) {
				// 如果服务被关闭，直接抛出拒绝执行异常
				throw new RejectedExecutionException(key);
			} else if (status == SvcConfig.STATUS_MOCKING) {
				// 如果开启了结果模拟功能，通过服务治理插件调用模拟器，返回模拟的结果
				return mock(key, rmc, args);
			}
		}
		if (rc.isGeneralized() || rc.getInterfaceClazz() == null) {
			RpcInvokeContext ric = RpcInvokeContext.getContext();
			ric.put(RpcConfig.TRACE_TAG, MDC.get(RpcConfig.TRACE_TAG));

			GenericObject genericObject = (GenericObject)args[0];
			AlipayGenericContext alipayGenericContext = new AlipayGenericContext();
			alipayGenericContext.setUid(String.valueOf(genericObject.getField("uid")));
			try {
				GenericService gs = (GenericService) ft.get(rmc.getTimeout(), TimeUnit.MILLISECONDS);
				log.debug("泛化调用{},AlipayGenericContext中uid为{}",rc.getInterfaceName().concat(rmc.getSign()),alipayGenericContext.getUid());
				Object ro = gs.$genericInvoke(mn, pm.split(","), args, alipayGenericContext);
				return GenObjConverter.convert(ro);
			} finally {
				ric.remove(RpcConfig.TRACE_TAG);
			}
		}
		// 如果存在本地RPC代理bean则走正常调用，反之走泛化调用
		Object po = null;
		String refId = rc.getId();
		// 先根据referenceId查找（但有可能传过来的refId与consume.xml中配置的不一致）
		if (Util.strIsNotEmpty(refId) && referMap.containsKey(refId)) {
			po = ((Future<Object>) referMap.get(refId)).get();
		}
		// 找不到再用接口类找符合sofa引用代理特征的bean
		if (po == null) {
			String n = rc.getInterfaceName();
			if (!referMap.containsKey(n)) {
				synchronized (referMap) {
					if (!referMap.containsKey(n)) {
						referMap.put(refId, this.findRefByCls(rc));
					}
				}
			}
			if (po == null) {
				po = ((Future<Object>) referMap.get(refId)).get();
			}
		}
		if (po == null) {
			throw new SofaRpcException(RpcErrorType.CLIENT_UNDECLARED_ERROR, //
					"Can not find SOFA reference bean ".concat(refId));
		}
		RpcInvokeContext ric = RpcInvokeContext.getContext();
		ric.put(RpcConfig.TRACE_TAG, MDC.get(RpcConfig.TRACE_TAG));
		try {
			// 通过反射调用SOFA Reference代理类
			return rmc.getMethod().invoke(po, args);
		} finally {
			ric.remove(RpcConfig.TRACE_TAG);
		}
	}

	protected Future<Object> findRefByCls(RpcReferenceConfig rc) {
		return RpcCore.getCurrentInstance().getThreadPool().submit(new Callable<Object>() {
			@Override
			public Object call() throws Exception {
				log.warn("Search sofa reference bean with class {}", rc.getInterfaceName());
				Class<?> pc = rc.getInterfaceClazz();
				if (pc != null) {
					Map<String, ?> map = applicationContext.getBeansOfType(pc);
					for (Object b : map.values()) {
						log.debug("Search sofa reference bean: {}", b.getClass().getName());
						if (b.getClass().getName().contains("proxy")) {
							return b;
						}
					}
				}
				return null;
			}
		});
	}

	public Object mock(String key, RpcMethodConfig rmc, Object[] args)
			throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		String m = rmc.getMocker();
		if (Util.strIsEmpty(m)) {
			log.warn("{} mocker config is missing", key);
			return null;
		}
		if (!applicationContext.containsBean(m)) {
			log.warn("{} mocker {} is not found", key, m);
			return null;
		}
		Object mocker = applicationContext.getBean(m);
		if (mocker instanceof RpcGenMocker) {
			RpcGenMocker rgm = (RpcGenMocker) mocker;
			return rgm.invoke(rmc, args);
		}
		Method method = rpcContext.getMyMethod(rmc.getRelativeId());
		return method.invoke(mocker, args);
	}

	public static SofaResponse mock(String key, SofaRequest req, Object mocker)
			throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		Object r = req.getMethod().invoke(mocker, req.getMethodArgs());
		SofaResponse sr = new SofaResponse();
		sr.setAppResponse(r);
		return sr;
	}

	@SuppressWarnings("unchecked")
	public Object checkOut(Object x) throws InstantiationException, IllegalAccessException {
		if (x == null) {
			return null;
		}
		Class<?> clazz = x.getClass();
		if (clazz.isPrimitive() || x instanceof String || x instanceof Byte || x instanceof Short || x instanceof Integer
				|| x instanceof Long || x instanceof Float || x instanceof Double || x instanceof Boolean
				|| x instanceof BigDecimal) {
			return x;
		}
		if (clazz.isArray()) {
			Object[] sa = (Object[]) x;
			Object[] ta = new Object[sa.length];
			for (int i = 0; i < sa.length; i++) {
				ta[i] = this.checkOut(sa[i]);
			}
			return ta;
		}
		if (clazz.isAssignableFrom(Collection.class)) {
			Collection<Object> sa = (Collection<Object>) x;
			Collection<Object> ta = (Collection<Object>) sa.getClass().newInstance();
			for (Object o : sa) {
				ta.add(this.checkIn(o));
			}
			return ta;
		}
		if (x instanceof GenericArray) {
			GenericArray g = new GenericArray("java.lang.Object");
			Object[] sa = ((GenericArray) x).getObjects();
			Object[] ta = new Object[sa.length];
			for (int i = 0; i < sa.length; i++) {
				ta[i] = this.checkIn(sa[i]);
			}
			g.setObjects(ta);
			return g;
		}
		if (x instanceof GenericObject) {
			GenericObject g = (GenericObject) x;
			RpcGenObj o = new RpcGenObj(g.getType());
			for (String k : g.getFieldNames()) {
				Object s = g.getField(k);
				Object t = this.checkOut(s);
				o.put(k, t);
			}
			return o;
		}
		if (x instanceof GenericCollection) {
			GenericCollection g = (GenericCollection) x;
			Collection<Object> sc = g.getCollection();
			Collection<Object> tc = sc.getClass().newInstance();
			for (Object s : sc) {
				Object t = this.checkOut(s);
				tc.add(t);
			}
			if (tc instanceof Set) {
				RpcGenSet o = new RpcGenSet(tc.getClass().getName(), (Set<Object>) tc);
				o.setElClzName(g.getType());
				return o;
			}
			if (tc instanceof List) {
				RpcGenList o = new RpcGenList(tc.getClass().getName(), (List<Object>) tc);
				o.setElClzName(g.getType());
				return o;
			}
		}
		if (x instanceof GenericMap) {
			GenericMap g = (GenericMap) x;
			Map<Object, Object> sm = g.getMap();
			Map<Object, Object> tm = sm.getClass().newInstance();
			for (Entry<?, ?> en : sm.entrySet()) {
				Object k = en.getKey();
				Object s = en.getValue();
				Object t = this.checkOut(s);
				tm.put(k, t);
			}
			RpcGenMap o = new RpcGenMap(sm.getClass().getName(), tm);
			o.setElClzName(g.getType());
			return o;
		}
		return x;
	}

	@SuppressWarnings("unchecked")
	public Object checkIn(Object x) throws InstantiationException, IllegalAccessException {
		if (x == null) {
			return null;
		}
		Class<?> clazz = x.getClass();
		if (clazz.isPrimitive() || x instanceof String || x instanceof Byte || x instanceof Short || x instanceof Integer
				|| x instanceof Long || x instanceof Float || x instanceof Double || x instanceof Boolean
				|| x instanceof BigDecimal) {
			return x;
		}
		if (clazz.isArray()) {
			Object[] sa = (Object[]) x;
			Object[] ta = new Object[sa.length];
			for (int i = 0; i < sa.length; i++) {
				ta[i] = this.checkIn(sa[i]);
			}
			return ta;
		}
		if (clazz.isAssignableFrom(Collection.class)) {
			Collection<Object> sa = (Collection<Object>) x;
			Collection<Object> ta = (Collection<Object>) sa.getClass().newInstance();
			for (Object o : sa) {
				ta.add(this.checkIn(o));
			}
			return ta;
		}
		if (x instanceof RpcGenArray) {
			RpcGenArray o = (RpcGenArray) x;
			GenericArray g = new GenericArray(o.getElClzName());
			Object[] sa = (Object[]) x;
			Object[] ta = new Object[sa.length];
			for (int i = 0; i < sa.length; i++) {
				ta[i] = this.checkIn(sa[i]);
			}
			g.setObjects(ta);
			return g;
		}
		if (x instanceof RpcGenObj) {
			RpcGenObj o = (RpcGenObj) x;
			GenericObject g = new GenericObject(o.getClazzName());
			for (Entry<String, Object> en : o.entrySet()) {
				String k = en.getKey();
				Object s = en.getValue();
				Object t = this.checkIn(s);
				g.putField(k, t);
			}
			return g;
		}
		if (x instanceof RpcGenSet || x instanceof RpcGenList) {
			RpcGenCollection sc = (RpcGenCollection) x;
			GenericCollection g = new GenericCollection(sc.getElClzName());
			g.setCollection(sc.getCollection().getClass().newInstance());
			Iterator<Object> z = sc.iterator();
			while (z.hasNext()) {
				Object s = z.next();
				Object t = this.checkIn(s);
				g.getCollection().add(t);
			}
			return g;
		}
		if (x instanceof RpcGenMap) {
			RpcGenMap o = (RpcGenMap) x;
			GenericMap g = new GenericMap(o.getElClzName());
			for (Entry<?, ?> en : o.entrySet()) {
				Object k = en.getKey();
				Object s = en.getValue();
				Object t = this.checkIn(s);
				g.getMap().put(k, t);
			}
			return g;
		}
		return x;
	}

	public String getRegAddress() {
		return regAddress;
	}

	public void setRegAddress(String regAddress) {
		this.regAddress = regAddress;
	}

	public int getLocalPort() {
		return localPort;
	}

	public void setLocalPort(int localPort) {
		this.localPort = localPort;
	}

	public String getAppName() {
		return appName;
	}

	public void setAppName(String appName) {
		this.appName = appName;
	}

	public String getRpcProtocol() {
		return rpcProtocol;
	}

	public void setRpcProtocol(String rpcProtocol) {
		this.rpcProtocol = rpcProtocol;
	}

	public String getRegProtocol() {
		return regProtocol;
	}

	public void setRegProtocol(String regProtocol) {
		this.regProtocol = regProtocol;
	}

	public int getRegistTimeout() {
		return registTimeout;
	}

	public void setRegistTimeout(int registTimeout) {
		this.registTimeout = registTimeout;
	}

	public int getAddressWait() {
		return addressWait;
	}

	public void setAddressWait(int addressWait) {
		this.addressWait = addressWait;
	}

	public static void main(String[] args) throws ClassNotFoundException {
		String fromJson = "{"//
				+ "   request: { custNo: \"001\" }, " //
				+ "   dataMap: { "//
				+ "     user: { name: \"tony\", age: 18 },"//
				+ "     list: [{"//
				+ "       a: { m: 1, n: 3 }, b: [11, 22]"//
				+ "     }, {"//
				+ "       a: { m: 2, n: 4 }, b: [33, 44]"//
				+ "     }]"//
				+ "   }"//
				+ "}";
		String toJson = "{}";
		JSONObject fromObj = JSONObject.parseObject(fromJson);
		JSONObject toObj = JSONObject.parseObject(toJson);

		String fromPath = "this.dataMap[user].age";
		String toPath = "this.data.group[0].users[].age";
		String toType = "java.math.BigDecimal";
		// user放到目标 userlist
		fromPath = "this.dataMap.user.name";
		toPath = "this.data.userlist[0].name";
		toType = "java.lang.String";
		mapping(fromObj, fromPath, toObj, toPath, toType);
		fromPath = "this.dataMap.user.age";
		toPath = "this.data.userlist[0].age";
		toType = "java.lang.String";
		mapping(fromObj, fromPath, toObj, toPath, toType);

		System.out.println(toObj);

		// jsonObject转为GenericObject
		// 假如目标对象为 DataDto{ userlist< User{name,age} > }
		toObj.put("custNo", 111);
		toObj.put("custName", "test");
		JSONObject data = (JSONObject) toObj.get("data");
		data.put("dataprop", "datatest");
		JSONArray userList = (JSONArray) data.get("userlist");
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("name", "aaa");
		jsonObject.put("age", 111);
		userList.add(jsonObject);
		System.out.println(toObj);
		// 最外层
		// String ReqClazz = "com.request.AAARequest";
		// GenericObject genericObject = new GenericObject(ReqClazz);
		// json2Generic(genericObject,toObj,ReqClazz);
		// System.out.println(genericObject);
	}

	public void json2Generic(GenericObject genericObject, JSONObject jsonObject, String clazz) {
		Set<Entry<String, Object>> entries = jsonObject.entrySet();
		for (Entry<String, Object> entry : entries) {
			Object x = entry.getValue();
			// 不是泛型
			if (x.getClass().isPrimitive() || x instanceof String || x instanceof Byte || x instanceof Short
					|| x instanceof Integer || x instanceof Long || x instanceof Float || x instanceof Double
					|| x instanceof Boolean || x instanceof BigDecimal) {
				genericObject.putField(entry.getKey(), x);
				continue;
			}

			if (entry.getValue() instanceof JSONObject) {
				// 数据库查询，根据当前genericObject的type【上级类路径】+当前属性名，获取当前属性的泛型类全路径
				String url = "http://127.0.0.1:8840/code/bean/prop/findPropType.do?name=".concat(entry.getKey())
						.concat("&beanClass=".concat(genericObject.getType()));
				String type = HttpClientUtil.sendGet(url);
				GenericObject genericObject1 = new GenericObject(type);
				json2Generic(genericObject1, (JSONObject) entry.getValue(), type);
				genericObject.putField(entry.getKey(), genericObject1);
				continue;
			}
			if (entry.getValue() instanceof JSONArray) {
				JSONArray jsonArray = (JSONArray) entry.getValue();
				List<GenericObject> genericObjects = new ArrayList<>();
				for (int i = 0; i < jsonArray.size(); i++) {
					String url = "http://127.0.0.1:8840/code/bean/prop/findPropType.do?name=".concat(entry.getKey())
							.concat("&beanClass=".concat(genericObject.getType()));
					String type = HttpClientUtil.sendGet(url);
					GenericObject genericObject1 = new GenericObject(type);
					json2Generic(genericObject1, (JSONObject) jsonArray.get(i), type);
					genericObjects.add(genericObject1);
				}
				genericObject.putField(entry.getKey(), genericObjects);
				continue;
			}
		}
	}

	public SvcSpy getSvcSpy() {
		return svcSpy;
	}

	public void setSvcSpy(SvcSpy svcSpy) {
		this.svcSpy = svcSpy;
	}

	public boolean isSubscribe() {
		return subscribe;
	}

	public void setSubscribe(boolean subscribe) {
		this.subscribe = subscribe;
	}

	public List<ProviderInfoListenerFactory> getListenerFactories() {
		return listenerFactories;
	}

	public void setListenerFactories(List<ProviderInfoListenerFactory> listenerFactories) {
		this.listenerFactories = listenerFactories;
	}

	@Override
	public String getProtocol() {
		return DEFAULT_PROTOCOL;
	}

	public boolean isSofaBoot() {
		return sofaBoot;
	}

	public void setSofaBoot(boolean sofaBoot) {
		this.sofaBoot = sofaBoot;
	}

}
